﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AForge.Video.FFMPEG;
using System.Drawing;

namespace VideoCoreWCF {
    public class VideoTrancodeReader : IDisposable {
        private Queue<Bitmap> m_buffers;
        private const int BUFFER_MAX = 300;
        /// <summary>
        /// 
        /// </summary>
        private VideoFileReader m_reader;
        private object m_locker = new object();
        /// <summary>
        /// Gets or sets the name of the file.
        /// </summary>
        /// <value>
        /// The name of the file.
        /// </value>
        private string FileName {
            get;
            set;
        }
        /// <summary>
        /// Gets or sets the current frame.
        /// </summary>
        /// <value>
        /// The current frame.
        /// </value>
        public long CurrentFrame {
            get;
            set;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="VideoTrancodeReader"/> class.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        public VideoTrancodeReader(string fileName) {
            CurrentFrame = 0;
            m_reader = new VideoFileReader();
            m_buffers = new Queue<Bitmap>(BUFFER_MAX);
            m_reader.Open(fileName);
            FileName = fileName;
        }
        /// <summary>
        /// Gets the frame.
        /// </summary>
        /// <param name="frameNo">The frame no.</param>
        /// <returns></returns>
        public Bitmap GetFrame(long frameNo) {
            if (frameNo < CurrentFrame) {
                // If the frame we retrive in buffers -->
                // Should be get it from buffers otherwise we should read from the begin
                //
                if (frameNo + m_buffers.Count < CurrentFrame) {
                    m_reader.Close();
                    m_reader.Open(FileName);
                    CurrentFrame = 0;
                    while (m_buffers.Count > 0) {
                        m_buffers.Dequeue().Dispose();
                    }

                    for (long i = 0; i < frameNo; i++) {
                        if (frameNo - i < BUFFER_MAX - 1) {
                            m_buffers.Enqueue(m_reader.ReadVideoFrame());
                            CurrentFrame++;
                        } else{
                            m_reader.ReadVideoFrame();
                            CurrentFrame++;    
                        }
                    }
                } else {
                    return m_buffers.ElementAt<Bitmap>((int)(m_buffers.Count + frameNo - CurrentFrame));
                }

            } else if (frameNo > CurrentFrame + 1) {
                for (long i = CurrentFrame; i < frameNo; i++) {
                    if (m_buffers.Count > BUFFER_MAX - 1) {
                        m_buffers.Dequeue().Dispose();
                    }
                    m_buffers.Enqueue(m_reader.ReadVideoFrame());
                    CurrentFrame++;
                }
            }
            CurrentFrame++;
            var bitmap = m_reader.ReadVideoFrame();
            if (m_buffers.Count == BUFFER_MAX){
                m_buffers.Dequeue().Dispose();
            }
            m_buffers.Enqueue(bitmap);
            return bitmap;
        }
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose() {
            while (m_buffers.Count > 0) {
                m_buffers.Dequeue().Dispose();
            }
            m_reader.Close();
            m_reader.Dispose();
        }
    }
}
